package com.zhuhjay.support.jackson;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.ContextualSerializer;
import com.zhuhjay.annotation.JsonDesensitization;

import java.io.IOException;

/**
 * jackson 脱敏序列化
 * @author ZhuHJay
 * @date 2023/2/12 16:54
 */
public class JsonDesensitizationSerializer extends JsonSerializer<String>
        implements ContextualSerializer {

    private JsonDesensitization desensitization;

    public JsonDesensitizationSerializer() { }

    public JsonDesensitizationSerializer(JsonDesensitization desensitization) {
        this.desensitization = desensitization;
    }

    @Override
    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        if (StrUtil.isBlank(value)) {
            gen.writeString(value);
            return;
        }
        if (desensitization != null) {
            final JsonDesensitization.Strategy strategy = desensitization.strategy();
            final int length = desensitization.length();
            final String replaceString = desensitization.replaceStr();
            gen.writeString(strategy.desensitization(value, length, replaceString));
        } else {
            gen.writeString(value);
        }
    }

    /**
     * 该序列化器可以根据所要序列化属性（实体类的属性）的类型或者配置的注解类型来改变该属性的序列化行为
     * @param prov 序列化器提供者，用于获取序列化配置或者其他序列化器
     * @param property 代表这个属性的方法或者字段，用于获取要序列化的值
     * @return 一个序列化器，根据所要实现的序列化行为来决定是返回当前序列化器还是新建一个序列化器，从而改变序列化时的行为。
     */
    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) {
        JsonDesensitization annotation = property.getAnnotation(JsonDesensitization.class);
        if (annotation != null) {
            return new JsonDesensitizationSerializer(annotation);
        }
        return this;
    }
}
